﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bluyel.Core
{
    //*************************************************************************
    /// <summary>
    /// A definition (item) of length physical qty prefix.
    /// </summary>
    class PhyLengthPrefixDef
    {
        bool _isPrefixCoeffPow10 = true; 

        /// <summary>
        /// The code or name.
        /// Identify the length prefix.
        /// </summary>
        public TypePhyLengthPrefix PrefixCode;

        /// <summary>
        /// The symbol of the prefix/multiple.
        /// 
        /// exp: "m" for Metre.
        /// </summary>
        public string Symbol;

        /// <summary>
        /// By default, the prefix coeff is a power of 10.
        /// </summary>
        // 
        public bool IsPrefixCoeffPow10 
        { get { return _isPrefixCoeffPow10; } } 

        /// <summary>
        /// Coefficient of the prefix, its value power of 10.
        /// Direction: xx -> metre (the reference) to this prefix.
        /// </summary>
        public double PrefixCoeffPow10 = 0;

        /// <summary>
        /// If the prefix coeff is not a power of 10, its a direct multiplicator.
        /// Used for Yard, Inch.
        /// Direction: xx -> metre (the reference) to this prefix.
        /// </summary>
        public double PrefixCoeffMul =0;

        /// <summary>
        /// Indicates if the prefix is defined in the SI
        /// ("Systeme Internationnal").
        /// </summary>
        public bool IsSI = true;

        /// <summary>
        /// Is it a common (usual) prefix?
        /// </summary>
        public bool Common;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="prefixCode"></param>
        /// <param name="coeff"></param>
        public PhyLengthPrefixDef(TypePhyLengthPrefix prefixCode, string symbol, double coeff, bool isSI, bool common)
        {
            PrefixCode = prefixCode;
            Symbol = symbol;
            PrefixCoeffPow10 = coeff;
            IsSI = isSI;
            Common = common;
        }

        public void SetPrefixCoeffMul(double val)
        {
            _isPrefixCoeffPow10 = false;
            PrefixCoeffMul = val;        
        }

    }

    //*************************************************************************
    /// <summary>
    /// Manage multiples and sub-multiples of the phys Qty Length.
    /// see: http://en.wikipedia.org/wiki/Metre
    /// 
    /// PhyLengthPrefixMgr
    /// </summary>
    public class PhyLengthPrefixMgr
    {
        // Code/Name, Value/CoeffToM, Symbol, Multiple/Sub-Multiple, SI/NoneSI, Common (Y/N)
        List<PhyLengthPrefixDef> _listItem = new List<PhyLengthPrefixDef>();

        //---------------------------------------------------------------------
        /// <summary>
        /// Constructor.
        /// </summary>
        public PhyLengthPrefixMgr()
        {
            BuildAllPrefixes();
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Get a coeff, from a source prefix to a target prefix.
        /// 
        /// exp: km -> cm: 2 steps km -> m, x10E3, m->cm, x10E2
        /// </summary>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public double GetCoeffByPrefix(TypePhyLengthPrefix prefixSrc, TypePhyLengthPrefix prefixTgt)
        {
            PhyLengthPrefixDef itemSrc = _listItem.Find(i => i.PrefixCode == prefixSrc);
            PhyLengthPrefixDef itemTgt = _listItem.Find(i => i.PrefixCode == prefixTgt);
            double coeff1 = 1;
            double coeff2 = 1;

            // source prefix and target prefix are equals: coeff=1 !
            if (prefixSrc == prefixTgt)
                return 1;

            // Step 1: prefix Source -> metre
            // If the coeff is not a power of 10 (for yard and Inch prefix)
            if (itemSrc.IsPrefixCoeffPow10)
                coeff1 = Math.Pow(10, itemSrc.PrefixCoeffPow10);
            else
                coeff1 = itemSrc.PrefixCoeffMul;

            // Step 1: metre -> prefixTgt
            if (itemTgt.IsPrefixCoeffPow10)
                coeff2 = Math.Pow(10, itemTgt.PrefixCoeffPow10 * -1);
            else
            {
                if (itemTgt.PrefixCoeffMul != 0)
                    coeff1 = 1 / itemTgt.PrefixCoeffMul;
                else
                    // pb!
                    coeff1 = 0;
            }
            return coeff1 * coeff2;
        }

        //---------------------------------------------------------------------
        private void BuildAllPrefixes()
        {
            PhyLengthPrefixDef item;
            // 10−24 m 	ym 	yoctometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Yoctometre, "ym", -24, true, false);
            _listItem.Add(item);

            // 10−21 m 	zm 	zeptometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Zeptometre, "zm", -21, true, false);
            _listItem.Add(item);

            // 10−18 m 	am 	attometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Attometre, "am", -18, true, false);
            _listItem.Add(item);

            // 10−15 m 	fm  femtometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Femtometre, "fm", -15, true, false);
            _listItem.Add(item);

            // 10−12 m  pm  picometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Picometre, "pm", -12, true, true);
            _listItem.Add(item);
        
            // 10−9 m 	nm 	nanometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Nanometre, "nm", -9, true,true);
            _listItem.Add(item);        

            // 10−6 m 	µm 	micrometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Micrometre, "µm", -6, true,true);
            _listItem.Add(item);
        
            // 10−3 m 	mm 	millimetre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Millimetre, "mm", -3, true,true);
            _listItem.Add(item);

            // 10−2 m 	cm 	centimetre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Centimetre, "cm", -2, true,true);
            _listItem.Add(item);

            // 10−1 m 	dm 	decimetre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Decimetre, "dm", -1, true, false);
            _listItem.Add(item);

            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Metre, "m", 0, true, true);
            _listItem.Add(item);

            // 10_1 m dam decametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Decametre, "dam", 1, true, false);
            _listItem.Add(item);

            // 10_2 m hm hectometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Hectometre, "hm", 2, true, false);
            _listItem.Add(item);

            // 10_3 m km kilometre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Kilometre, "km", 3, true, true);
            _listItem.Add(item);

            // 10_6 m Mm megametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Megametre, "Mm", 6, true, false);
            _listItem.Add(item);
            
            // 10_9 m Gm gigametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Gigametre, "Gm", 9, true, false);
            _listItem.Add(item);
            
            // 10_12 m Tm terametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Terametre, "Tm", 12, true, false);
            _listItem.Add(item);
            
            // 10_15 m Pm petametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Petametre, "Pm", 15, true, false);
            _listItem.Add(item);
            
            // 10_18 m Em exametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Exametre, "Em", 18, true, false);
            _listItem.Add(item);
            

            // 10_21 m Zm zettametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Zettametre, "Zm", 21, true, false);
            _listItem.Add(item);
            
            // 10_24 m Ym yottametre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Yottametre, "Ym", 24, true, false);
            _listItem.Add(item);
            

            //----None SI 
            // 10-10 m ångström
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Angstrom, "a??", -10, false, false);
            _listItem.Add(item);
        
            // 1 yard= 0.9144 metre
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Yard, "a??", 0, false, false);
            item.SetPrefixCoeffMul(0.9144);
            _listItem.Add(item);

            //1 inch= 0.0254 metres
            item = new PhyLengthPrefixDef(TypePhyLengthPrefix.Inch, "in", 0, false, false);
            item.SetPrefixCoeffMul(0.0254);
            _listItem.Add(item);
        
        }
    }
}
